package com.infolab.aims.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.elixirtech.ers2.client.ERSClient;
import com.elixirtech.job.IJobInfo;
import com.elixirtech.net.NetException;
import com.infolab.aims.GlobalConstant;
import com.infolab.aims.common.CommonUtil;
import com.infolab.aims.domain.Location;
import com.infolab.aims.domain.Report;
import com.infolab.aims.domain.asset.AssetBalance;
import com.infolab.aims.domain.asset.AssetModel;
import com.infolab.aims.service.intf.ReportService;

@Service
@Transactional
public class ReportServiceImpl implements ReportService {
	
	Log logger = LogFactory.getLog(getClass());
	
	@PersistenceContext
	private EntityManager em;
	
	private @Value("${reportElixirServerHost:\"\"}") String reportElixirServerHost;
	
	private @Value("${reportElixirServerPort:\"\"}") Integer reportElixirServerPort;
	
	private @Value("${reportElixirServerUsername:\"\"}") String reportElixirServerUsername;
	
	private @Value("${reportElixirServerPassword:\"\"}") String reportElixirServerPassword;
	
	private @Value("${reportDirectory:\"\"}") String reportDirectory;
	
	private @Value("${reportTempDirectory:\"\"}") String reportTempDirectory;
	
	private static Map<String, String> SORT_MAP = new HashMap<String, String>();
	static{
		SORT_MAP.put("locationid", "Location");
		SORT_MAP.put("assetModelcode", "Asset Model");
		SORT_MAP.put("companyCode", "Company Code");
		SORT_MAP.put("assetType", "Asset Type");
		SORT_MAP.put("locationname", "Location");
		SORT_MAP.put("assetModelname", "Asset Model");
		SORT_MAP.put("serialNo", "Serial No");
		SORT_MAP.put("inventory_type", "Asset Type");
	}
	
	
	
	
	public void createNewReport(Report report)
	{
		report.setDateCreated(new Date());
		
		Report newReport= new Report();
		report.setModifiedBy(report.getCreatedBy());
		report.setDateCreated(new Date());
		report.setDateModified(new Date());
		report.setReportStatus(Report.REPORTSTATUS_INPROCESS);
		String reportId = DigestUtils.md5Hex(report.getCreatedBy()+report.getDateCreated().getTime());
		report.setReportId(reportId);
		BeanUtils.copyProperties(report,newReport);
		
		em.persist(newReport);
		
	}

	@Async
	public void processReport(Report report, List<Location> list) {
		
		logger.info("Start process "+report.getReportFileName());
		FileOutputStream out = null;
		boolean failed =false;
		try {
			
			Date reportDate = report.getDateCreated();
			String fileExt= ".xls";
			String mimeType = GlobalConstant.MIME_XLS;
			if(report.isPdfReport()) {
				fileExt = ".pdf";
				mimeType = GlobalConstant.MIME_PDF;
			}
			String folderName = reportDirectory+File.separatorChar+DateFormatUtils.format(reportDate, "yyyyMM")+File.separatorChar+report.getCreatedBy()+File.separatorChar;
			new File(folderName).mkdirs();
			String fileName = folderName+report.getReportId()+fileExt;
			out = new FileOutputStream(new File(fileName));
			
			
			ERSClient client = new ERSClient(reportElixirServerHost, reportElixirServerPort, reportElixirServerUsername, reportElixirServerPassword);
			
			
			int recordCount = renderReport(client,report,list,mimeType,out);
			if(recordCount<=1)
				report.setReportStatus(Report.REPORTSTATUS_NORECORD);
			else
				report.setReportStatus(Report.REPORTSTATUS_SUCCESS);
			
			
			
			report.setReportFileName(DateFormatUtils.format(reportDate, "yyyyMM")+File.separatorChar+report.getCreatedBy()+File.separatorChar+report.getReportId()+fileExt);
			
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			failed=true;
			logger.error(CommonUtil.getStackTrace(e));
			
		} finally {
			if(failed)
				report.setReportStatus(Report.REPORTSTATUS_FAIL);
			
			em.merge(report);
			
			if(out!=null)
				try {
					out.close();
				} catch (IOException e) {
					logger.error(CommonUtil.getStackTrace(e));
				}
		}
		
		logger.info("End process "+report.getReportFileName());
	}

	private int renderReport(ERSClient client, Report report, List<Location> list, String mimeType,
			FileOutputStream out) throws NetException {
	
		Properties properties = new Properties();
		int recordCount = 1;
		IJobInfo iJobInfo = null;
		
		String startDate = report.getSearch().get("startDate");
		String endDate = report.getSearch().get("endDate");
		String companyCode = report.getSearch().get("companyCode");
		String personName = report.getSearch().get("personName");
		
		//for report NV06
		String serialNo=report.getSearch().get("serialNo");
		String locationId=report.getSearch().get("locationId");

		if(StringUtils.isNotEmpty(startDate))
			properties.setProperty("startDate", startDate);
		if(StringUtils.isNotEmpty(endDate))
			properties.setProperty("endDate", endDate);
		if(StringUtils.isNotEmpty(companyCode))
			properties.setProperty("companyCode", companyCode);
		if(StringUtils.isNotEmpty(personName))
			properties.setProperty("personName", personName);
		
		//Add all the loacation infomation
		StringBuilder sb = new StringBuilder();
		sb.append("The following is glossary of location: \r\n");
		for(Location location : list){
			sb.append(location.getLocationCode() + ":" + location.getLocationName() + " \r\n");
		}
		properties.setProperty("locations", sb.toString());
		
		//set never timeout
		client.setTimeout(0);
		if(StringUtils.equalsIgnoreCase(report.getSubModule(),"R01"))
			 iJobInfo =  client.renderReport("/AIMS_Reports/Report/VisitorAccessDetail.rml", mimeType, out, properties);			
		else if(StringUtils.equalsIgnoreCase(report.getSubModule(),"R02"))
			iJobInfo = client.renderReport("/AIMS_Reports/Report/VisitorStatistic.rml", mimeType, out, properties);
		else if(StringUtils.equalsIgnoreCase(report.getSubModule(),"R03"))
			 iJobInfo = client.renderReport("/AIMS_Reports/Report/SecurityGuardAttendent.rml", mimeType, out, properties);
		else if(StringUtils.equalsIgnoreCase(report.getSubModule(),"R04")){
			iJobInfo = client.renderReport("/AIMS_Reports/Report/SecurityGuardKPI.rml", mimeType, out, properties);
		}
		
		if(iJobInfo!=null)
			recordCount = iJobInfo.getInteger(iJobInfo.RECORD_COUNT);
		
		return recordCount;
	}
	
	private boolean isLastMonthClosed(String month, String year){
		//delete first
		Query assetBlance = em.createQuery("from AssetBalance assetBalance where assetBalanceMonth = :month and assetBalanceYear = :year");
		assetBlance.setParameter("month", month);
		assetBlance.setParameter("year", year);
		List<AssetBalance> resultList = assetBlance.getResultList();
		if(CollectionUtils.isNotEmpty(resultList)){
			return true;
		}
		return false;
	}

	public Report getReport(String reportId) {
		return em.find(Report.class, reportId);
	}

	public String getReportDirectory() {
		return reportDirectory;
	}
}
